using System;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using PHSRAG.Insight21.CDS;
using PHSRAG.Insight21.Common.Pages;
using PHSRAG.Insight21.Context;
using PHSRAG.Insight21.FormsManagement;
using PHSRAG.Insight21.Policy;
using PHSRAG.Insight21.ScriptEngine;
using PHSRAG.Security.Enumerations;
using PHSRAG.Utility;
using ScriptReference = PHSRAG.Insight21.ScriptEngine.ScriptReference;

namespace PHSRAG.Insight21.Humans.Details
{
    /// <summary>
    /// Tracking page for those staffed to a protocol, and who have access to the protocol.  Certain
    /// values on the page are editable if the user has access to do this.  This page also launches 
    /// processes for adding study staff, as well as adding access to non-study staff.
    /// </summary>
    public partial class StaffAndAccess : BasePage
    {
        #region Instance Variables (Private)

        private ICachePolicy cachePolicy;
        private string newRole;
        private string oldRole;
        private Hashtable pageCache;
        private ICachePolicy pageCachePolicy;
        private Protocol protocol;
        private int protocolId;
        private int protocolProcessId;        

        /// <summary>
        ///This flag is used to decide whether or not the headers should be displayed
        ///If the page is to be displayed as a popup, then the header section is made invisible
        /// </summary>
        private bool showAsPopUp;

        /// <summary>
        /// access the user has to the protocol
        /// </summary>
        private int userAccessLevel;

        #endregion

        #region Protected members

        protected string board;

        #endregion

        #region Constants

        private const string AdmPersonIdAttributeName = "AdmPersonId";
        private const string AnnunciatorTitle = "The following error(s) occurred...";
        private const string CachedProcessIdKey = "cachedProcIdKey_9572FCDE-47B6-4e7b-921E-D32AE6F02D45";
        private const string CachedProtocolIdKey = "cachedProtIdKey_9572FCDE-47B6-4e7b-921E-D32AE6F02D45";
        private const string PageCacheKey = "Staff&APageKey_9572FCDE-47B6-4e7b-921E-D32AE6F02D45";
        private const string PermissionsBitValueColumn = "BitValue";
        private const string PermissionsKey = "permissionsKey_9572FCDE-47B6-4e7b-921E-D32AE6F02D45";
        private const string PermissionsNameColumn = "Name";
        private const string PIIRoleTyped = "13";
        private const string roleDropDownListId = "roles";
        private const string roleLabelId = "editRoleLabel";
        private const string RolesKey = "rolesKey_9572FCDE-47B6-4e7b-921E-D32AE6F02D45";
        private const string RoleTypeIdAttributeName = "RoleTypeId";
        private const string SitePIIRoleTyped = "1";
        private const string StudyStaffListKey = "studystaffListKey_9572FCDE-47B6-4e7b-921E-D32AE6F02D45";

        #endregion

        #region Web Form Designer generated code

        /// <summary>
        /// Initializes the page, sets up caching policies
        /// </summary>
        /// <param name="e">arguments from the event</param>
        protected override void OnInit(EventArgs e)
        {
            //
            // CODEGEN: This call is required by the ASP.NET Web Form Designer.
            //
            InitializeComponent();
            base.OnInit(e);

            cachePolicy = (Policy.ICachePolicy) Session[Policy.Names.CachePolicyKey];
            pageCachePolicy = (Policy.ICachePolicy) Session[Policy.Names.PageCachePolicyKey];
        }

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.header.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnNavigate);
            this.humansSubModuleNavigation.Navigate += new PHSRAG.Insight21.InsightWebControls.HumansSubModuleNavigation.NavigateEventHandler(this.OnHumansSubModNavigate);
            this.animalsSubModuleNavigation.Navigate += new CommandEventHandler(this.OnHumansSubModNavigate);
            this.breadCrumb.Navigate += new System.Web.UI.WebControls.CommandEventHandler(this.OnBreadCrumbNavigate);
            this.addSubmitterToStaff.Click += new System.Web.UI.ImageClickEventHandler(this.OnAddSubmitterToStaff);
            this.staffGrid.ItemCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.OnStaffItemCommand);
            this.staffGrid.CancelCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.OnCancelStaffPerson);
            this.staffGrid.EditCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.OnEditStaffPerson);
            this.staffGrid.UpdateCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.OnUpdateStaffPerson);
            this.staffGrid.ItemDataBound += new System.Web.UI.WebControls.DataGridItemEventHandler(this.OnStaffItemDataBound);
            this.addStaff.Click += new System.Web.UI.ImageClickEventHandler(this.OnAddStaff);
            this.nonStudyStaffGrid.CancelCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.OnCancelNonStaffPerson);
            this.nonStudyStaffGrid.EditCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.OnEditNonStaffPerson);
            this.nonStudyStaffGrid.UpdateCommand += new System.Web.UI.WebControls.DataGridCommandEventHandler(this.OnUpdateNonStaffPerson);
            this.nonStudyStaffGrid.ItemDataBound += new System.Web.UI.WebControls.DataGridItemEventHandler(this.OnNonStaffItemDataBound);
            this.addUsers.Click += new System.Web.UI.ImageClickEventHandler(this.OnAddUsers);
            this.Load += new System.EventHandler(this.OnPageLoad);
        }

        #endregion

        #region Private Properties

        /// <summary>
        /// Checks if the page should have editable fields -- 
        /// Returns true if:
        /// (1) The page is in the context of the protocol and it is unlocked OR
        /// (2) The page is in the context of a process and it has a status of 
        /// "In Progress", "Submitted", or "Pending"
        /// (Note that the logged-in user must have edit or manage access
        /// to edit anything; must have manage access to edit permissions)
        /// --Contact and Permissions columns will always be editable if the
        /// logged-in user has Manage access
        /// </summary>
        private bool IsAllEditable
        {
            get
            {
                if ((protocolProcessId == 0) && !Protocol.IsLocked)
                {
                    return true;
                }
                if (protocolProcessId > 0)
                {
                    string status = ProtocolProcess.Status;
                    return ((status == Constants.ProtocolProcessStatus.WorkInProgress) ||
                        (!ProtocolProcess.Locked));
                }
                return false;
            }
        }

        /// <summary>
        /// Indicates whether staffing updates must persist in REX; setter gets used if 
        /// contact designation changes
        /// </summary>
        private bool MustUpdateREX
        {
            get
            {
                // we can't add a check on whether the protocol is locked because the user's
                // can change contact person designation on locked protocols and these changes
                // need to make it to REX
                if (protocolProcessId == 0)
                {
                    return true;
                }

                return
                    protocolProcessId > 0 &&
                        (ProtocolProcess.Type == Constants.ProtocolProcessType.InitialReview ||
                            ProtocolProcess.Type == Constants.AnimalProtocolProcessType.InitialReview) &&
                                protocol.ProtocolNumber != null && protocol.ProtocolNumber.Trim().Length > 0;
            }
        }

        /// <summary>
        /// Gets the protocol for which staffing is being reviewed or modified.  If it's not already
        /// in the cache, it loads it up based on the protocolId passed to the page, and caches the object
        /// </summary>
        private Protocol Protocol
        {
            get
            {
                string cacheKey = Protocol.ProtocolKey;
                protocol = cachePolicy.GetCachedObject(cacheKey) as Protocol;

                if ((protocol == null) || (protocolId != protocol.Id))
                {
                    protocol = new Protocol(cachePolicy);
                    protocol.Load(DataAccess.GetConnectionString(), protocolId);
                    cachePolicy.Cache(cacheKey, protocol);
                }
                return protocol;
            }
        }

        /// <summary>
        /// Gets the protocol process for which staffing is being reviewed or modified.  If it's not already
        /// in the cache, it loads it up based on the protocolProcessId passed to the page, and caches the 
        /// object
        /// </summary>
        private ProtocolProcess ProtocolProcess
        {
            get
            {
                ProtocolProcess protocolProcess =
                    cachePolicy.GetCachedObject(ProtocolProcess.ProtocolProcessKey)
                        as ProtocolProcess;

                if ((protocolProcess == null) || (protocolProcessId != protocolProcess.Id))
                {
                    if (protocolProcessId > 0)
                    {
                        protocolProcess = ProtocolProcess.GetProtocolProcess(
                            DataAccess.GetConnectionString(), protocolProcessId, cachePolicy, null);
                        cachePolicy.Cache(ProtocolProcess.ProtocolProcessKey, protocolProcess);
                    }
                    else
                    {
                        protocolProcess = null;
                    }
                }
                return protocolProcess;
            }
        }

        /// <summary>
        /// Get the list of possible access levels to a protocol (rows of bitvalue/name pairs).
        /// This maintains the relationship between access levels and their bitvalues for binding
        /// to the Permissions dropdownlists
        /// </summary>
        private DataTable Permissions
        {
            get
            {
                DataTable permissions = pageCache[PermissionsKey] as DataTable;
                if (permissions == null)
                {
                    permissions = Protocol.GetAccessLevels(DataAccess.ConnectionString, Protocol.ModuleType);
                    pageCache[PermissionsKey] = permissions;
                    pageCachePolicy.Cache(PageCacheKey, pageCache);
                }
                return permissions;
            }
        }

        /// <summary>
        /// Gets the list of roles that a person can be staffed to for a study (rows of id/name pairs).
        /// This maintains the relationship between roles and their IDs for binding to the Roles 
        /// dropdownlists
        /// </summary>
        private DataTable Roles
        {
            get
            {
                if (Protocol != null && Protocol.ModuleType == "A")
                {
                    return (DataTable) cachePolicy.GetCachedObject(InsightUtilities.Constants.AnimalsRolesKey);
                }

                return (DataTable) cachePolicy.GetCachedObject(InsightUtilities.Constants.HumansRolesKey);
            }
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Resets the hash table that stores page data to an empty structure and removes the cached 
        /// ProtocolId and the cached ProtocolProcessId, from the cache (which indicate which protocol
        /// the cached page data is based on)
        /// </summary>
        private void UnCachePageData()
        {
            pageCachePolicy.UnCache(CachedProtocolIdKey);
            pageCachePolicy.UnCache(CachedProcessIdKey);

            pageCache = new Hashtable();
            pageCachePolicy.Cache(PageCacheKey, pageCache);
        }

        /// <summary>
        /// Loads external staff along with the organization in the drop down
        /// </summary>
        private void LoadStaffWithoutCertification()
        {
            ddlSelectedExternalPeople.Items.Clear();
            ArrayList staff = (protocolProcessId == 0) ? Protocol.StudyStaffList : ProtocolProcess.StudyStaff;
            ArrayList staffWithoutConsentForm = new ArrayList();
            foreach (StaffPerson sp in staff)
            {
                if (sp.ConsentForm == null && !string.IsNullOrEmpty(sp.Role))
                {
                    staffWithoutConsentForm.Add(sp);
                    //ddlSelectedExternalPeople.Items.Add(new ListItem(sp.FullNameAndRole, sp.Id.ToString()));
                    //ddlSelectedExternalPeople.Items[ddlSelectedExternalPeople.Items.Count - 1].Attributes.Add(AdmPersonIdAttributeName, sp.AdmPersonId.ToString());
                    //ddlSelectedExternalPeople.Items[ddlSelectedExternalPeople.Items.Count - 1].Attributes.Add(RoleTypeIdAttributeName, sp.RoleId.ToString());
                }
            }

            ddlSelectedExternalPeople.DataSource = staffWithoutConsentForm;
            ddlSelectedExternalPeople.DataTextField = "FullNameAndRole";
            ddlSelectedExternalPeople.DataValueField = "Id";
            ddlSelectedExternalPeople.DataBind();
            pnlCertificationFormUploadSection.Visible = staffWithoutConsentForm.Count > 0;
        }

        /// <summary>
        /// Shows or hides the certification form upload section based on the user access level
        /// </summary>
        private void ToggleCertificationFormUploadSectionVisibility()
        {
            //should be loaded on initial request and subsequent postbacks to reflect any role changes
            UserContext userContext = (UserContext) cachePolicy.GetCachedObject(UserContext.CacheKey);
            if ((userContext.ModuleRoleBitmask & (int) ModuleRoleBit.WorkflowManager) > 0)
            {
                LoadStaffWithoutCertification();
            }
        }

        /// <summary>
        /// Compares the protocolId and protocolProcessId to the ones that the page has cached 
        /// data for (if any).  If these IDs differ, the Staff and Non-Staff data is purged from
        /// the cache.
        /// </summary>
        private void EnsureCurrentCache()
        {
            /* We need to purge the cache if:
			 * (1) The ProtocolProcessId is not the same as the one we have cached data for OR
			 * (2) The stored data is based on a protocolProcess since we are currently viewing staff 
			 * for the entire protocol, not just a process 
			 * (3) Tje stored data is based on a protocol, but not the one we need to show staff for*/

            if (((protocolProcessId > 0) &&
                (Convert.ToInt32(pageCache[CachedProcessIdKey]) != protocolProcessId)) ||
                    ((protocolProcessId == 0) &&
                        (((pageCache.ContainsKey(CachedProcessIdKey) && (int) pageCache[CachedProcessIdKey] > 0))
                            || (Convert.ToInt32(pageCache[CachedProtocolIdKey]) != protocolId))))
            {
                UnCachePageData();
            }
        }

        /// <summary>
        /// Sets the datasource for the grid displaying study staff and binds it.
        /// The label displaying the number of records gets set here also.
        /// </summary>
        private void BindStaffGrid()
        {
            staffGrid.DataSource =
                (protocolProcessId == 0) ? Protocol.StudyStaffList : ProtocolProcess.StudyStaff;
            staffGrid.DataBind();
            recordCount.Text = staffGrid.Items.Count.ToString();
        }

        /// <summary>
        /// Sets the datasource for the grid displaying nonstudystaff and binds it.  The label
        /// displaying the number of records gets set also.
        /// </summary>
        private void BindNonStaffGrid()
        {
            nonStudyStaffGrid.DataSource =
                (protocolProcessId == 0) ? Protocol.NonStudyStaff : ProtocolProcess.NonStudyStaff;
            nonStudyStaffGrid.DataBind();
            nonStudyStaffCount.Text = nonStudyStaffGrid.Items.Count.ToString();
        }

        /// <summary>
        /// Displays the submitter on the page
        /// </summary>
        private void BindSubmitter()
        {
            if (0 == protocolProcessId)
            {
                return;
            }

            submitter.Text = Person.GetPersonByUserId(DataAccess.ConnectionString, cachePolicy, ProtocolProcess.SubmitterId).FullName;
        }

        /// <summary>
        /// Given a bitmask, determines the max permission the bitmask is composed of.  (If the user was
        /// given access to the study through the Admin module, the access level might be an aggregate)
        /// </summary>
        /// <param name="bitmask">bitmask to examine for the max factor</param>
        /// <returns>the maximum permission this bitmask masks</returns>
        private int CalculateMaxPermission(int bitmask)
        {
            int permission = 0;
            for (int i = 0, count = Permissions.Rows.Count; i < count; ++i)
            {
                int potentialMaxPermission = (int) Permissions.Rows[i][PermissionsBitValueColumn];
                if ((bitmask & potentialMaxPermission) > permission)
                {
                    permission = potentialMaxPermission;
                }
            }
            return permission;
        }

        /// <summary>
        /// Determines whether the person's role is editable
        /// </summary>
        /// <param name="person">person whose role we are questioning</param>
        /// <returns>true if changing the role is allowed</returns>
        private bool CheckRoleMaintainability(StaffPerson person)
        {
            return (IsAllEditable &&
                ((protocolProcessId == 0) ||
                    (person.AddedProtocolProcessId == protocolProcessId)));
        }

        /// <summary>
        /// Determines whether the person's role is editable based on the processId
        /// </summary>
        /// <returns>true if changing the role is allowed</returns>
        private bool CheckRoleMaintainability(int addedProcessId)
        {
            return (IsAllEditable &&
                ((protocolProcessId == 0) ||
                    (addedProcessId == protocolProcessId)));
        }

        /// <summary>
        /// Formats the Certification date column; A different style is applied
        /// based on whether or not the person has a current certification
        /// (and "Yes" or "No" is displayed)
        /// </summary>
        /// <param name="item">the datagriditem to format</param>
        private void DisplayCertification(DataGridItem item)
        {
            if (Protocol.ModuleType == Constants.ModuleType.Animals)
            {
                TableCell cert = item.Cells[(int) StaffColumnIndex.CertificationDate];
                if (Protocol.SpeciesCode != null && Protocol.SpeciesCode.StartsWith("MONKEYS"))
                {
                    if (((StaffPerson) item.DataItem).IsOCCHealthCertified)
                    {
                        cert.Text = "Yes";
                        cert.CssClass = "DataGridCertifiedItem";
                    }
                    else
                    {
                        cert.Text = "No";
                        cert.CssClass = "DataGridNotCertifiedItem";
                    }
                }
                else
                {
                    cert.Text = "";
                }
            }
        }

        /// <summary>
        /// Formats the CITI Certification column; A different style is applied
        /// based on whether or not the person has a current CITI certification
        /// (and "Yes" or "No" is displayed)
        /// </summary>
        /// <param name="item">the datagriditem to format</param>
        private void DisplayCITI(DataGridItem item)
        {
            TableCell citi = item.Cells[(int) StaffColumnIndex.CitiCertified];
            if (Protocol.ModuleType == Constants.ModuleType.Animals)
            {
                if (((StaffPerson) item.DataItem).IsOrientated)
                {
                    citi.Text = "Yes";
                    citi.CssClass = "DataGridCertifiedItem";
                }
                else
                {
                    citi.CssClass = "DataGridNotCertifiedItem";
                    citi.Text = "No";
                }
            }
            else
            {
                if (((StaffPerson) item.DataItem).Person.IsCitiCertified)
                {
                    citi.Text = "Yes";
                    citi.CssClass = "DataGridCertifiedItem";
                }
                else
                {
                    citi.CssClass = "DataGridNotCertifiedItem";
                    citi.Text = "No";
                }
            }
        }

        /// <summary>
        /// Determines whether the staff person has signed the Consent Form; 
        /// If yes, displays the PDF image
        /// </summary>
        /// <param name="item">datagriditem to format</param>
        private void DisplayConsentForm(DataGridItem item)
        {
            ImageButton viewConsent = (ImageButton) item.FindControl("viewConsent");
            if (((StaffPerson) item.DataItem).ConsentForm == null)
            {
                viewConsent.Visible = false;
            }
            else
            {
                viewConsent.Visible = true;
                viewConsent.ImageUrl = @"~/Images/pdf.jpg";
            }
        }

        /// <summary>
        /// Displays the relevant controls based on whether this item is being edited,
        /// and whether this user has manage access.
        /// If this item is being edited, and the user is internal (has a username and
        /// thus can log in to the system), set and bind the permissions dropdownlist.
        /// However, if the logged-in user doesn't have manage access, disable the ddl.
        /// If the user is not internal, show nothing. 
        /// If the item is not being edited, create a label to display the permission
        /// level (or none, if the user is external).
        /// </summary>
        /// <param name="item">the datagriditem being bound</param>
        private void DisplayPermission(DataGridItem item)
        {
            StaffPerson person = (StaffPerson) item.DataItem;
            int permission = CalculateMaxPermission(person.PermissionLevel);

            if (item.ItemIndex == staffGrid.EditItemIndex)
            {
                DropDownList permissions = item.Cells[(int) StaffColumnIndex.Permission].Controls[1] as DropDownList;
                /* if this person doesn't have access, we don't want to allow changing of 
				* access through the front-end */
                if (permissions != null)
                {
                    if (permission == 0)
                    {
                        item.Cells[(int) StaffColumnIndex.Permission].Controls.Remove(permissions);
                    }
                    else
                    {
                        string roleId = (CheckRoleMaintainability(person)) ?
                                                                               ((DropDownList) item.Cells[(int) StaffColumnIndex.Role].
                                                                                   FindControl(roleDropDownListId)).SelectedValue
                            : ((int) Roles.Select(string.Format("Name = '{0}'",
                                ((Label) item.Cells[(int) StaffColumnIndex.Role].
                                    FindControl(roleLabelId)).Text))[0]["Id"]).ToString();

                        bool isPIOrSitePI =
                            (roleId == PIIRoleTyped) || (roleId == SitePIIRoleTyped);

                        permissions.DataSource = Permissions;
                        permissions.DataTextField = PermissionsNameColumn;
                        permissions.DataValueField = PermissionsBitValueColumn;
                        permissions.DataBind();
                        permissions.Enabled = !isPIOrSitePI &&
                            (userAccessLevel & Protocol.ManagePermission) > 0;
                        permissions.SelectedValue = permission.ToString();
                    }
                }
            }
            else
            {
                Label permissions =
                    item.Cells[(int) StaffColumnIndex.Permission].Controls[1] as Label;
                if (permissions != null)
                {
                    permissions.Text = (permission == 0) ? string.Empty :
                                                                            (string) Permissions.Select(
                                                                                String.Format("BitValue = {0}", permission))[0]["Name"];
                }
            }
        }

        /// <summary>
        /// Handles display of the role column.  Role should be editable if the
        /// item is editable, and if the person has been added during this process
        /// (or the protocol is unlocked and we are in the context of a protocol)
        /// </summary>
        /// <param name="item">DataGridItem to format</param>
        /// <returns>id of the role the person has been assigned</returns>
        private int DisplayRole(DataGridItem item)
        {
            int roleId = 0;
            if (item.ItemIndex == staffGrid.EditItemIndex)
            {
                TableCell cell = item.Cells[(int) StaffColumnIndex.Role];
                DropDownList roles = cell.FindControl(roleDropDownListId) as DropDownList;
                Label role = cell.FindControl(roleLabelId) as Label;
                StaffPerson staff = (StaffPerson) item.DataItem;
                // no longer allow editing for people that were added during another
                // process -- if the role needs to be modified, the user needs to remove
                // the person, and re-staff him/her. 
                if (CheckRoleMaintainability(staff))
                {
                    if (roles != null)
                    {
                        roleId = ((StaffPerson) item.DataItem).RoleId;

                        roles.Visible = true;
                        if (role != null)
                        {
                            role.Visible = false;
                        }

                        roles.DataSource = Roles;
                        roles.DataTextField = "Name";
                        roles.DataValueField = "Id";
                        roles.SelectedValue = roleId.ToString();
                        roles.DataBind();
                        roles.Items.Remove(roles.Items.FindByText("Gets Mail"));
                    }
                }
                else
                {
                    if (roles != null)
                    {
                        roles.Visible = false;
                    }
                    if (role != null)
                    {
                        role.Visible = true;
                        role.Text = ((StaffPerson) item.DataItem).Role;
                        roleId = (int) Roles.Select(string.Format("Name = '{0}'", role.Text))[0]["Id"];
                    }
                }
            }
            else
            {
                Label role = item.Cells[(int) StaffColumnIndex.Role].Controls[1] as Label;
                if (role != null)
                {
                    role.Text = ((StaffPerson) item.DataItem).Role;
                    roleId = (int) Roles.Select(string.Format("Name = '{0}'", role.Text))[0]["Id"];
                }
            }
            return roleId;
        }

        /// <summary>
        /// Checks if the warning message to the user should be displayed,
        /// </summary>
        private void HandleSavePrompt()
        {
            if (staffGrid.EditItemIndex > -1 || nonStudyStaffGrid.EditItemIndex > -1)
            {
                warning.Visible = true;
                throw new Exception("User must save changes");
            }
        }

        /// <summary>
        /// Stores the data relevant to the destination page in a hashtable and caches it under 
        /// the IncomingData key
        /// </summary>
        private void CacheOutgoingData(bool showTargetAsPopUp)
        {
            Hashtable outgoingData = new Hashtable();
            outgoingData.Add(Keys.ProtocolIdKey, protocolId);
            outgoingData.Add(Keys.ProtocolAccessKey, userAccessLevel);
            outgoingData.Add(Keys.ProtocolProcessIdKey, protocolProcessId);
            outgoingData.Add(Keys.ShowAsPopUp, showTargetAsPopUp);
            pageCachePolicy.Cache(Keys.IncomingDataKey, outgoingData);
        }

        /// <summary>
        /// Removes the StaffPerson corresponding to the DataGridItem from the study
        /// </summary>
        /// <param name="item">item in the DataGrid that has been checked for removal</param>
        private void RemoveStaffPerson(DataGridItem item)
        {
            ProtocolProcess process = null;
            SqlConnection conn = new SqlConnection(DataAccess.GetConnectionString());
            SqlTransaction trans = null;

            try
            {
                conn.Open();
                trans = conn.BeginTransaction();
                StaffPerson person;

                if (protocolProcessId > 0)
                {
                    process = ProtocolProcess;
                    person = (StaffPerson) process.StudyStaff[item.ItemIndex];
                    process.RemoveStudyStaff(DataAccess.ConnectionString, person);
                    if (MustUpdateREX)
                    {
                        process.UpdateStaffInREX(DataAccess.GetConnectionString(),
                            DataAccess.GetConnectionString(InsightUtilities.Constants.RexDatabaseKey), protocol);
                    }
                }
                else
                {
                    Protocol protocol = Protocol;
                    person = (StaffPerson) protocol.StudyStaffList[item.ItemIndex];
                    protocol.RemoveStudyStaff(DataAccess.ConnectionString, person);
                    Protocol.UpdateStaffInREX(DataAccess.GetConnectionString(),
                        DataAccess.GetConnectionString(InsightUtilities.Constants.RexDatabaseKey));
                }

                // Remove the PI Information from the protocol if it's an unlocked protocol
                // or an initial review (otherwise need to wait to update the protocol
                // until the process has been approved)
                if (((protocolProcessId == 0) || (process.Type ==
                    Constants.ProtocolProcessType.InitialReview) ||
                        (process.Type == Constants.AnimalProtocolProcessType.InitialReview)) &&
                            (person.RoleId == Convert.ToInt32(PIIRoleTyped)))
                {
                    protocol.PIPersonId = protocol.OrganizationId = 0;
                    protocol.PIName = string.Empty;
                    protocol.Save(trans);
                }

                UpdateAMEForm(person, false);

                trans.Commit();
            }
            catch (Exception ex)
            {
                trans.Rollback();
                ExceptionReport.WriteToEventLog(
                    "StaffAndAccess", ex, true, ExceptionReport.ReportType.Error);
                annunciator.Message = "The changes you made failed to save";
            }
            finally
            {
                if (conn.State != ConnectionState.Closed)
                {
                    conn.Close();
                }
            }
        }

        /// <summary>
        /// Updates attributes on the StaffPerson object (does not persist these changes into the database)
        /// </summary>
        /// <param name="person">StaffPerson to update</param>
        /// <param name="item">item in the dataGrid corresponding to the StaffPerson to update</param>
        private void UpdateStaffPersonObject(StaffPerson person, DataGridItem item)
        {
            person.ModuleType = protocol.ModuleType;

            /* Check if this person's permission level is 0.  If it is, they cannot be assigned access 
					 * b/c they may be external, and won't have a username */
            string selectedValue =
                ((DropDownList) item.Cells[(int) StaffColumnIndex.Permission].Controls[1]).SelectedValue;
            person.PermissionLevel =
                (selectedValue == string.Empty) ? 0 : Convert.ToInt32(selectedValue);


            // Don't bother to update the role if it shouldn't be changeable
            if (CheckRoleMaintainability(person))
            {
                //Save the old role to be used while filling up the AME form
                oldRole = person.Role;

                person.RoleId = Convert.ToInt32(((DropDownList) item.Cells[(int) StaffColumnIndex.Role].
                    FindControl(roleDropDownListId)).SelectedValue);

                //Save the new role
                newRole = ((DropDownList) item.Cells[(int) StaffColumnIndex.Role].
                    FindControl(roleDropDownListId)).SelectedItem.Text;
            }

            person.IsContactPerson =
                ((CheckBox) item.Cells[(int) StaffColumnIndex.ContactPerson].Controls[1]).Checked;
        }

        /// <summary>
        /// Checks if there is currently a PI staffed to the protocol.  If there is, and the user is 
        /// attempting to staff the currently selected person as the PI, do not allow this update.  
        /// </summary>
        /// <param name="person">Person the user is attempting to update</param>
        /// <returns>Whether the update is allowed (false if attempting to staff a 2nd PI)</returns>
        private bool PermitStaffingUpdate(StaffPerson person, DataGridItem item)
        {
            DropDownList roles =
                (DropDownList) item.Cells[(int) StaffColumnIndex.Role].FindControl(roleDropDownListId);

            // we're not enforcing the single PI rule HERE during an amendment; this should be caught
            // during validation
            if ((protocolProcessId > 0) &&
                (ProtocolProcess.Type != Constants.ProtocolProcessType.InitialReview) &&
                    (ProtocolProcess.Type != Constants.AnimalProtocolProcessType.InitialReview))
            {
                return true;
            }

            if ((roles.SelectedValue == PIIRoleTyped) && (protocol.PIPersonId > 0) &&
                (protocol.PIPersonId != person.Person.Id))
            {
                annunciator.Message = @"There is already a PI staffed to this study.  More than one
						PI may not be staffed.";
                return false;
            }

            return true;
        }

        /// <summary>
        /// Updates the protocol object and persists it to reflect the staffed PI and the PI's org, in 
        /// the case that this data has just changed (The PI/Org on the protocol needs to be updated if 
        /// the PI has changed unless it's not an Initial Review (i.e. if it's an Amendment, 
        /// the PI on the protocol wont' persist until it has been approved)
        /// 
        /// Also: Updates the protocol in REX with the updated PI info
        /// </summary>
        /// <param name="person">StaffPerson that was just updated</param>
        /// <param name="trans">transaction to use to perform the updates</param>
        private void UpdateProtocol(StaffPerson person, SqlTransaction trans)
        {
            bool updateProtocol = false;
            ProtocolProcess process;
            if (protocolProcessId > 0)
            {
                process = ProtocolProcess;
                if (process.Type == Constants.ProtocolProcessType.InitialReview || process.Type == Constants.AnimalProtocolProcessType.InitialReview)
                {
                    /* If there was a PI staffed to the protocol preceding this update, 
					remove it if there is no longer a PI staffed.  We use the process
					to determine the staffing, but we want to set it on the Protocol */
                    if (!process.HasPI
                        && protocol.PIPersonId > 0 && person.RoleId != Convert.ToInt32(PIIRoleTyped))
                    {
                        protocol.PIPersonId = protocol.OrganizationId = 0;
                        protocol.PIName = string.Empty;
                        updateProtocol = true;
                    }

                        /* If there was NOT a PI staffed to the protocol preceding this update, and one 
						was just staffed, update the cached protocol */
                    else if ((person.RoleId == Convert.ToInt32(PIIRoleTyped)) && (protocol.PIPersonId == 0))
                    {
                        UpdatePIOnProtocolObject(protocol, person);
                        updateProtocol = true;
                    }
                }
            }
            else
            {
                if ((protocol.PIPersonId == person.Person.Id) && (person.RoleId != Convert.ToInt32(PIIRoleTyped)))
                {
                    protocol.PIPersonId = protocol.OrganizationId = 0;
                    protocol.PIName = string.Empty;
                    updateProtocol = true;
                }
                else if (person.RoleId == Convert.ToInt32(PIIRoleTyped))
                {
                    UpdatePIOnProtocolObject(protocol, person);
                    updateProtocol = true;
                }
            }

            // if the protocol doesn't have a protocol number, it hasn't been 
            // submitted to REX yet, so no updates need to persist there
            // todo:  only do this if updateProtocol is true?
            if (MustUpdateREX)
            {
                try
                {
                    if (protocolProcessId > 0)
                    {
                        ProtocolProcess.UpdateStaffInREX(DataAccess.GetConnectionString(),
                            DataAccess.GetConnectionString(InsightUtilities.Constants.RexDatabaseKey),
                            protocol);
                    }
                    else
                    {
                        protocol.UpdateStaffInREX(DataAccess.GetConnectionString(),
                            DataAccess.GetConnectionString(InsightUtilities.Constants.RexDatabaseKey));
                    }
                }
                catch (Exception)
                {
                    protocol.PIPersonId = protocol.OrganizationId = 0;
                    protocol.PIName = string.Empty;
                    throw;
                }
            }

            if (updateProtocol)
            {
                protocol.Save(trans);
            }
        }

        /// <summary>
        /// Updates the Protocol's PI with the passed in person.  PI-related information
        /// gets set on the Protocol object (the protocol's org and administrator)
        /// </summary>
        /// <param name="protocol">Protocol object to update</param>
        /// <param name="person">person to set as PI</param>
        private void UpdatePIOnProtocolObject(Protocol protocol, StaffPerson person)
        {
            protocol.PIPersonId = person.Person.Id;
            protocol.PIName = String.Format("{0}, {1}", person.LastName, person.FirstName);
            int orgId = person.OrganizationId;
            protocol.OrganizationId = orgId;
            Organization piOrg = new Organization(cachePolicy);
            piOrg.Load(DataAccess.GetConnectionString(), orgId);
            protocol.AdministratorId = (protocol.ModuleType.ToUpper() == "H") ? piOrg.ProtocolAdministratorId : piOrg.AnimalsProtocolAdministratorId;
        }

        /// <summary>
        /// Displays an error message on the screen to the user with the exception, and all
        /// inner exception messages.
        /// </summary>
        /// <param name="ex">The exception to report on</param>
        private void DisplayExceptionReport(Exception ex)
        {
            annunciator.Title = AnnunciatorTitle;
            annunciator.Message = ExceptionReport.GetExceptionInfo(ex, false);

            submitterPanel.Visible = false;
        }

        private void UpdateAMEForm(StaffPerson person, bool adding)
        {
            if (protocolProcessId != 0 && (ProtocolProcess.Type == Constants.ProtocolProcessType.Amendment
                || ProtocolProcess.Type == Constants.AnimalProtocolProcessType.Amendment))
            {
                ProtocolVersion protocolVersion = ProtocolProcess.GetLatestProtocolVersion(DataAccess.ConnectionString,
                    false, cachePolicy);

                //Invoke the TrackStaffChanges script. 
                QuestionnaireAnswer questAnswer;
                if (Protocol.ModuleType == Constants.ModuleType.Animals)
                {
                    questAnswer = protocolVersion.GetQuestionnaireAnswers(FormsManagement.Constants.AnimalsFormCatgory.Amendment)[0] as QuestionnaireAnswer;
                }
                else
                {
                    questAnswer = protocolVersion.GetQuestionnaireAnswers(FormsManagement.Constants.AmmendmentCategory.InitialQuestionnaire)[0] as QuestionnaireAnswer;
                }
                Script trackStaffChangesScript =
                    (Script) questAnswer.QuestionnaireVersion.Scripts[ScriptEngine.Constants.ScriptType.TrackStaffChanges];

                if (trackStaffChangesScript != null)
                {
                    using (ScriptEngineHost scriptHost =
                        new ScriptEngineHost(
                            string.Format("{0}{1}", questAnswer.QuestionnaireVersionId,
                                ScriptEngine.Constants.RootMoniker.TrackStaffChangesScriptMoniker),
                            ScriptEngine.Constants.RootNamespaces.TrackStaffChangesScript,
                            true))
                    {
                        ArrayList refs = ScriptReference.GetAllScriptReferences(
                            DataAccess.GetConnectionString());

                        for (int i = 0; i < refs.Count; ++i)
                        {
                            ScriptReference reference = (ScriptReference) refs[i];
                            scriptHost.AddDLLReference(reference.Path);
                        }

                        // add the connection string
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.ConnectionString,
                            DataAccess.GetConnectionString());
                        // add the caching policy
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.CachePolicy, cachePolicy);
                        // add this Protocol as an intrinsic.
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.Protocol, Protocol);
                        // add this ProtocolProcess as an intrinsic.
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.ProtocolProcss, ProtocolProcess);
                        // add this ProtocolVersion as an intrinsic.
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.ProtocolVersion, protocolVersion);

                        // add the QuestionnaireAnswer
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.QuestionnaireAnswer,
                            questAnswer);

                        // add the staffperson
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.StaffPerson, person);

                        //flag to indicate whether the staffPerson is being added or removed
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.IsStaffBeingAdded, adding);

                        //old and new roles of the staff
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.OldStaffRole, oldRole);
                        scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.NewStaffRole, newRole);

                        // compile and run the script.
                        if (scriptHost.Compile(trackStaffChangesScript))
                        {
                            scriptHost.RunScript(trackStaffChangesScript,
                                ScriptEngine.Constants.AssemblyType.TrackStaffChangesScript,
                                ScriptEngine.Constants.MethodsToRun.Main);
                        }
                    }
                }
            }
        }

        #endregion

        #region Protected Methods

        /// <summary>
        /// Make necessary changes to page for use by Animals or Humans
        /// </summary>
        protected void SetupPageForModuleType()
        {
            if (Protocol.ModuleType == Constants.ModuleType.Animals)
            {
                animalsSubModuleNavigation.Visible = true;
                humansSubModuleNavigation.Visible = false;
                animalsSubModuleNavigation.ProtocolProcess = ProtocolProcess;
                animalsSubModuleNavigation.Protocol = Protocol;
                animalsSubModuleNavigation.SelectedLink = "Staff & Access";
                board = "IACUC";
            }
            else
            {
                humansSubModuleNavigation.Visible = true;
                animalsSubModuleNavigation.Visible = false;
                humansSubModuleNavigation.ProtocolProcess = ProtocolProcess;
                humansSubModuleNavigation.Protocol = Protocol;
                humansSubModuleNavigation.SelectedLink = "Staff & Access";
                board = "IRB";
            }
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// On the first page load only, data is removed from the cache and placed into the hashtable 
        /// maintained by the page.  Based on the presence of certain keys in the incoming pagehash, 
        /// certain data elements on the page may get reloaded.  The grids are bound to their data, and 
        /// the arraylist that maintains the binding between access levels and their bitvalues gets 
        /// populated with data.  Finally, if the user doesn't have Manage or Edit access to the protocol, 
        /// certain things on the page are disabled or hidden.
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        protected void OnPageLoad(object sender, EventArgs e)
        {
            try
            {
                breadCrumb.Add(
                    "Staff & Access",
                    Settings.GetKeyValue("SubModuleNavigation.Humans.StaffAndAccessURL", ""),
                    Settings.GetKeyValue("BreadCrumb.DetailPageLevel", 2));

                pageCache = pageCachePolicy.GetCachedObject(PageCacheKey) as Hashtable;

                // get id coming from the originating page and clean the cache of all incoming data
                Hashtable incomingPageHash = cachePolicy.GetCachedObject(Keys.IncomingDataKey) as Hashtable;

                #region NonPostBack

                if (!IsPostBack && postbackGuard.IsValid && (incomingPageHash != null))
                {
                    UserContext userContext = cachePolicy.GetCachedObject(UserContext.CacheKey) as UserContext;
                    System.Diagnostics.Trace.Assert(userContext != null);

                    Person currentUser = new Person(cachePolicy);
                    currentUser.Load(DataAccess.GetConnectionString(), userContext.PersonId);

                    // Pull incoming data out of cache and store under the page's cache
                    protocolId = Convert.ToInt32(incomingPageHash[Keys.ProtocolIdKey]);
                    protocolProcessId = Convert.ToInt32(incomingPageHash[Keys.ProtocolProcessIdKey]);
                    userAccessLevel = Convert.ToInt32(incomingPageHash[Keys.ProtocolAccessKey]);
                    if (incomingPageHash.ContainsKey(Keys.ShowAsPopUp))
                    {
                        showAsPopUp = Convert.ToBoolean(incomingPageHash[Keys.ShowAsPopUp]);
                    }

                    if (incomingPageHash.Contains(Keys.ProtocolReloadStaffKey) &&
                        (bool) incomingPageHash[Keys.ProtocolReloadStaffKey])
                    {
                        /* also uncache and rebind the nonstaff grid in case a staff person was just added 
						 * that had access (so they won't appear in the nonstaff grid) */
                        if (protocolProcessId != 0)
                        {
                            ProtocolProcess.StudyStaff = null;
                            ProtocolProcess.NonStudyStaff = null;
                        }
                        else
                        {
                            Protocol.StudyStaffList = null;
                            Protocol.NonStudyStaff = null;
                        }
                    }

                    // Other pages can modify the data on this page.  If the data was modified, the page
                    // will put a key into the hash to indicate a reload is necessary
                    if (incomingPageHash.Contains(Keys.ProtocolReloadNonStaffKey) &&
                        (bool) incomingPageHash[Keys.ProtocolReloadNonStaffKey])
                    {
                        if (protocolProcessId != 0)
                        {
                            ProtocolProcess.NonStudyStaff = null;
                        }
                        else
                        {
                            Protocol.NonStudyStaff = null;
                        }
                    }

                    cachePolicy.UnCache(Keys.IncomingDataKey);

                    if (Protocol.ModuleType == Constants.ModuleType.Humans ||
                        currentUser.GetCertificationQuestionnaireAnswer(DataAccess.ConnectionString,
                            FormsManagement.Constants.AnimalsQuestionnaireCommonFormNames.OccHealth) == null)
                    {
                        pnlOccHealth.Visible = false;
                    }

                    ToggleCertificationFormUploadSectionVisibility();

                    // check if previously cached protocolId matches the current protocolId
                    // (or processId matches current procedssId); if 
                    // they don't match, we need to remove the cached data
                    if (pageCache != null)
                    {
                        EnsureCurrentCache();
                    }
                    else
                    {
                        pageCache = new Hashtable();
                    }

                    pageCache[CachedProtocolIdKey] = pageCache[Keys.ProtocolIdKey] = protocolId;
                    pageCache[CachedProcessIdKey] = pageCache[Keys.ProtocolProcessIdKey] = protocolProcessId;
                    pageCache[Keys.ProtocolAccessKey] = userAccessLevel;
                    pageCache[Keys.ProtocolProcessIdKey] = protocolProcessId;
                    pageCache[Keys.ShowAsPopUp] = showAsPopUp;
                    pageCachePolicy.Cache(PageCacheKey, pageCache);

                    BindStaffGrid();
                    BindNonStaffGrid();
                    BindSubmitter();
                }
                    #endregion Nonpostback
                    /* Either this is a postback, the post isn't valid or the incomingPageHash is null: We need 
					 * this in case page loaded, nothing was clicked, and a refresh ensued (a non-postback, but 
					 * now the cache is flushed) */
                else
                {
                    protocolId = (int) pageCache[Keys.ProtocolIdKey];
                    protocolProcessId = (int) pageCache[Keys.ProtocolProcessIdKey];
                    userAccessLevel = (int) pageCache[Keys.ProtocolAccessKey];
                    showAsPopUp = (bool) pageCache[Keys.ShowAsPopUp];
                }


                //if page is being shown as popup, then hide the header section
                headerSection.Visible = !showAsPopUp;

                if ((((userAccessLevel & Protocol.ManagePermission) > 0)
                    || ((userAccessLevel & Protocol.EditPermission) > 0)))
                {
                    /* user has access to modify data */
                    addUsers.Visible = true;
                    addStaff.Visible = IsAllEditable;
                }                    
                else /* hide "add access" button and directions*/
                {
                    studyStaffDirections.Visible =
                        addUsers.Visible =
                            addStaff.Visible = false;
                }

                // if there is no proccess, page is a popup, or the current user does not
                // have Manager access, hide all the Submitter altering controls
                if (0 == protocolProcessId || showAsPopUp)
                {
                    submitterPanel.Visible = false;
                }
                else
                {
                    if (ProtocolProcess.Locked ||
                        0 == (userAccessLevel & Protocol.ManagePermission))
                    {
                        submitterPanel.Visible = false;
                    }
                    else if (Constants.ProtocolProcessStatus.WorkInProgress != ProtocolProcess.Status)
                    {
                        addSubmitterToStaff.Visible = false;
                    }
                }

                addSubmitterToStaff.Visible = true;

                SetupPageForModuleType();

                //remove edit column and add nonstudystaff button if this is an amendment
                if ((ProtocolProcess != null) && (ProtocolProcess.Name.Contains("AME")))
                {
                    addUsers.Visible = nonStudyStaffGrid.Columns[(int)NonStaffColumnIndex.Edit].Visible = false;
                }
                
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
            finally
            {
                protocolDetailHeader.ProtocolID = protocolId;
                //Set the humansubmodule Navigation links
            }
        }

        /// <summary>
        /// Handles the Init event on staff grid.  We use this to conditionally change some 
        /// column properties.  Handling it here makes the changes happen at each load, whether
        /// it's a postback or not.  If you only do this in OnPageLoad, and an event is raised
        /// from a control in a template column, the changes do not persist.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void OnStaffGridInit(object sender, EventArgs e)
        {
            if (header.ModuleName == InsightUtilities.Constants.Modules.Animals)
            {
                BoundColumn orientationColumn = new BoundColumn();
                orientationColumn.DataField = "IsOrientated";
                orientationColumn.HeaderText = "Orientation";
                orientationColumn.ReadOnly = true;
                staffGrid.Columns.RemoveAt((int) StaffColumnIndex.CitiCertified);
                staffGrid.Columns.AddAt((int) StaffColumnIndex.CitiCertified, orientationColumn);

                TemplateColumn occHealthClearanceDate = new TemplateColumn();
                occHealthClearanceDate.HeaderText = "OCC Health Clearance";
                staffGrid.Columns.RemoveAt((int) StaffColumnIndex.CertificationDate);
                staffGrid.Columns.AddAt((int) StaffColumnIndex.CertificationDate, occHealthClearanceDate);
                staffGrid.Columns[9].HeaderText = "AM/TR";
            }
        }

        /// <summary>
        /// Stores the document corresponding to the image on which the user clicks in the cache. 
        /// Registers a script that will pop up a new window and loads the downloadform.aspx
        /// The downloadform displays the file represented by the cached Document.
        /// </summary>
        /// <param name="source">object that raised the event</param>
        /// <param name="e">arguments of the event</param>
        protected void OnStaffItemCommand(object source, DataGridCommandEventArgs e)
        {
            try
            {
                if (!postbackGuard.IsValid)
                {
                    return;
                }

                if (e.CommandName == "ImageClick")
                {
                    StaffPerson person = (StaffPerson) ((protocolProcessId == 0) ? Protocol.StudyStaffList : ProtocolProcess.StudyStaff)[e.Item.ItemIndex];

                    Hashtable outgoingData = new Hashtable();
                    outgoingData[Keys.DocumentKey] = person.ConsentForm;
                    //Script for popup window that displays the attachment
                    string script = "\n<script language=JavaScript id='DisplayAttachment'>\n" +
                        "window.open('DownloadForm.aspx', 'ViewFile', 'resizable=yes, status=yes, scrollbars=yes'); \n" +
                            "</script>";

                    if (!ClientScript.IsClientScriptBlockRegistered("DisplayAttachment"))
                    {
                        ClientScript.RegisterClientScriptBlock(GetType(), "DisplayAttachment", script);
                    }
                    pageCachePolicy.Cache(Keys.IncomingDataKey, outgoingData);
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Populates values for template columns.  If the item is being edited, the editable fields
        /// are made editable here; Organization name is formatted; Color and value of whether the person 
        /// is citi certfied gets determined here
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnStaffItemDataBound(object sender, DataGridItemEventArgs e)
        {
            try
            {
                if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem ||
                    e.Item.ItemType == ListItemType.EditItem)
                {
                    StaffPerson staffPerson = (StaffPerson) e.Item.DataItem;
                    // strip out "Partners >" from the beginning of the fully qualified org name, if it exists
                    e.Item.Cells[(int) StaffColumnIndex.Organization].Text =
                        Organization.StripDomain(staffPerson.OrganizationName);

                    DisplayCITI(e.Item);
                    DisplayCertification(e.Item);
                    DisplayConsentForm(e.Item);
                    string roleId = DisplayRole(e.Item).ToString();
                    // Permissions need to be calculated AFTER role since they are dependent
                    DisplayPermission(e.Item);

                    // Contact and Permissions of PI/Site PI shouldn't be editable
                    bool isPIOrSitePI = false;

                    DropDownList roles = e.Item.Cells[(int) StaffColumnIndex.Role].
                        FindControl(roleDropDownListId) as DropDownList;
                    if (roles != null)
                    {
                        isPIOrSitePI =
                            (roleId == PIIRoleTyped) || (roleId == SitePIIRoleTyped);
                    }

                    CheckBox contact = e.Item.Cells[(int) StaffColumnIndex.ContactPerson].Controls[1]
                        as CheckBox;
                    if (contact != null)
                    {
                        contact.Checked = staffPerson.IsContactPerson;
                    }
                    contact.Enabled =
                        (e.Item.ItemIndex == staffGrid.EditItemIndex) && !isPIOrSitePI;

                    CheckBox remove = e.Item.Cells[(int) StaffColumnIndex.Remove].Controls[1]
                        as CheckBox;
                    if (remove != null)
                    {
                        remove.Enabled = (e.Item.ItemIndex == staffGrid.EditItemIndex)
                            && IsAllEditable;
                    }

                    //Fill the amendment column with process name only if the process is an amendment
                    Label ameNumber = (Label) e.Item.FindControl("ameNumber");
                    if (staffPerson.ProcessType == Constants.ProtocolProcessType.Amendment
                        || staffPerson.ProcessType == Constants.AnimalProtocolProcessType.Amendment
                            || staffPerson.ProcessType == Constants.AnimalProtocolProcessType.TriennialReview)
                    {
                        ameNumber.Text = staffPerson.ProcessName;
                    }

                    Label status = (Label) e.Item.FindControl("status");
                    status.Text = staffPerson.Status;
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Populates values for template columns.  If the item is being edited, the editable fields
        /// are made editable here; Organization name is formatted; 
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnNonStaffItemDataBound(object sender, DataGridItemEventArgs e)
        {
            try
            {
                if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem ||
                    e.Item.ItemType == ListItemType.EditItem)
                {
                    // strip out "Partners >" from the beginning of the fully qualified org name, if it exists
                    e.Item.Cells[(int) NonStaffColumnIndex.Organization].Text =
                        Organization.StripDomain(((NonStaffPerson) e.Item.DataItem).OrganizationName);

                    CheckBox cb =
                        e.Item.Cells[(int) NonStaffColumnIndex.ContactPerson].Controls[1] as CheckBox;
                    if (cb != null)
                    {
                        cb.Checked = ((NonStaffPerson) e.Item.DataItem).IsContactPerson;
                    }

                    CheckBox remove =
                        e.Item.Cells[(int) NonStaffColumnIndex.Remove].Controls[1] as CheckBox;

                    int permission = CalculateMaxPermission(((NonStaffPerson) e.Item.DataItem).PermissionLevel);

                    if (e.Item.ItemIndex == nonStudyStaffGrid.EditItemIndex)
                    {
                        DropDownList permissions =
                            e.Item.Cells[(int) NonStaffColumnIndex.Permission].Controls[1] as DropDownList;
                        if (permissions != null)
                        {
                            permissions.DataSource = Permissions;
                            permissions.DataTextField = PermissionsNameColumn;
                            permissions.DataValueField = PermissionsBitValueColumn;
                            permissions.DataBind();
                            permissions.Enabled =
                                (userAccessLevel & Protocol.ManagePermission) > 0;
                            permissions.SelectedValue = permission.ToString();
                        }

                        cb.Enabled = remove.Enabled = true;

                        TextBox tb =
                            e.Item.Cells[(int) NonStaffColumnIndex.Comments].Controls[1] as TextBox;
                        if (tb != null)
                        {
                            tb.Text = ((NonStaffPerson) e.Item.DataItem).Comments;
                            tb.Rows = (tb.Text == string.Empty) ? 1 : 2;
                        }
                    }
                    else
                    {
                        /*Item is not being edited */

                        Label comments = e.Item.Cells[(int) NonStaffColumnIndex.Comments].Controls[1] as Label;
                        if (comments != null)
                        {
                            comments.Text = ((NonStaffPerson) e.Item.DataItem).Comments;
                        }

                        Label permissions = e.Item.Cells[(int) NonStaffColumnIndex.Permission].Controls[1]
                            as Label;
                        permissions.Text = (permission == 0) ? string.Empty :
                                                                                (string) Permissions.Select(
                                                                                    String.Format("BitValue = {0}", permission))[0]["Name"];

                        cb.Enabled = remove.Enabled = false;
                    }
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Resets the subnavigation selected link before the breadCrumb performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnBreadCrumbNavigate(object sender, CommandEventArgs e)
        {
            HandleSavePrompt();
            humansSubModuleNavigation.Reset();
        }

        /// <summary>
        /// Resets the subnavigation selected link before the header performs a redirect.
        /// </summary>
        /// <param name="sender">Control which rasied the event.</param>
        /// <param name="e">Arguments associated with the event.</param>
        private void OnNavigate(object sender, CommandEventArgs e)
        {
            HandleSavePrompt();
            try
            {
                humansSubModuleNavigation.Reset();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Constructs and caches a hashtable of data for use by the page to which nagivation leads
        /// </summary>
        private void OnHumansSubModNavigate(object sender, EventArgs e)
        {
            OnHumansSubModNavigate();
        }

        /// <summary>
        /// Constructs and caches a hashtable of data for use by the page to which nagivation leads
        /// </summary>
        private void OnHumansSubModNavigate()
        {
            HandleSavePrompt();

            try
            {
                CacheOutgoingData(false);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Caches outgoing data for the wizard, then redirects to the appropriate page
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnAddUsers(object sender, ImageClickEventArgs e)
        {
            try
            {
                if (staffGrid.EditItemIndex > -1 || nonStudyStaffGrid.EditItemIndex > -1)
                {
                    warning.Visible = true;
                    return;
                }
                CacheOutgoingData(showAsPopUp);
                Response.Redirect(Settings.GetKeyValue("SubModuleNavigation.Humans.AddNonStaffURL",
                    "AddNonStaff.aspx"), false);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Sets the index of the item being edited and refreshes the nonstaff grid
        /// </summary>
        /// <param name="source">source of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnEditNonStaffPerson(object source,
            DataGridCommandEventArgs e)
        {
            try
            {
                if (staffGrid.EditItemIndex > -1 || nonStudyStaffGrid.EditItemIndex > -1)
                {
                    warning.Visible = true;
                    return;
                }

                nonStudyStaffGrid.EditItemIndex = e.Item.ItemIndex;
                BindNonStaffGrid();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Resets the index of the item being edited to -1 and refreshes the nonstaff grid
        /// </summary>
        /// <param name="source">source of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnCancelNonStaffPerson(object source, DataGridCommandEventArgs e)
        {
            try
            {
                nonStudyStaffGrid.EditItemIndex = -1;
                BindNonStaffGrid();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// The record being edited gets cast to a NonStaffPerson.  If the record is checked for removal, 
        /// the NonStaffPerson is removed, otherwise, the editable values are set on the NonStaffPerson
        /// and it is called on to save itself.  The index of the item is then reset to -1 and the nonstaff 
        /// grid is refreshed to reflect the updates
        /// </summary>
        /// <param name="source">source of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnUpdateNonStaffPerson(object source, DataGridCommandEventArgs e)
        {
            try
            {
                NonStaffPerson person;
                if (protocolProcessId != 0)
                {
                    person = (NonStaffPerson) ProtocolProcess.NonStudyStaff[e.Item.ItemIndex];
                }
                else
                {
                    person = (NonStaffPerson) Protocol.NonStudyStaff[e.Item.ItemIndex];
                }                

                if (((CheckBox) e.Item.Cells[(int) NonStaffColumnIndex.Remove].Controls[1]).Checked)
                {
                    person.Delete(DataAccess.GetConnectionString());

                    person.MarkForDelete = true;
                    person.IsContactPerson = false;

                    UndateNonStudyStaff(e);

                    person.MarkForDelete = false;
                    // reload the non study staff
                    if (protocolProcessId != 0)
                        ProtocolProcess.NonStudyStaff = null;
                    else
                        Protocol.NonStudyStaff = null;
                }
                else
                {
                    person.Comments =
                        ((TextBox) e.Item.Cells[(int) NonStaffColumnIndex.Comments].Controls[1]).Text;
                    person.PermissionLevel = Convert.ToInt32(((DropDownList)
                        e.Item.Cells[(int) NonStaffColumnIndex.Permission].Controls[1]).SelectedValue);
                    person.IsContactPerson =
                        ((CheckBox) e.Item.Cells[(int) NonStaffColumnIndex.ContactPerson].Controls[1]).Checked;

                    UndateNonStudyStaff(e);
                    
                    person.Save(DataAccess.GetConnectionString());                                        
                }
                
                nonStudyStaffGrid.EditItemIndex = -1;
                BindNonStaffGrid();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        private void UndateNonStudyStaff(DataGridCommandEventArgs e)
        {
            NonStaffPerson person;
            
            if (protocolProcessId != 0)
            {
                person = (NonStaffPerson)ProtocolProcess.NonStudyStaff[e.Item.ItemIndex];
            }
            else
            {
                person = (NonStaffPerson)Protocol.NonStudyStaff[e.Item.ItemIndex];
            } 

            //if protocol is Active it is asumed that it is already in Rex, at this point it can not find
            //protocolProcess because there are multiple instances for the same protocol (initial, ame etc..)
            //that is why I am checking if Protocol is Active always update non study staff.
            if ((Protocol.OverallStatus == "Active") || (ProtocolProcess == null))
            {
                protocol.UpdateSingleNonStudyStaffInREX(DataAccess.ConnectionString,
                            DataAccess.GetConnectionString(InsightUtilities.Constants.RexDatabaseKey), protocol, person.Id, person.IsContactPerson);
            }
            else if (ProtocolProcess != null)
            {
                if (ProtocolProcess.MovedToRex == 1)
                {
                    protocol.UpdateSingleNonStudyStaffInREX(DataAccess.ConnectionString,
                                DataAccess.GetConnectionString(InsightUtilities.Constants.RexDatabaseKey), protocol, person.Id, person.IsContactPerson);
                }
            }
        }

        /// <summary>
        /// Resets the index of the item being edited to -1 and refreshes the staff grid
        /// </summary>
        /// <param name="source">source of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnCancelStaffPerson(object source, DataGridCommandEventArgs e)
        {
            try
            {
                warning.Visible = false;
                staffGrid.EditItemIndex = -1;
                BindStaffGrid();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Sets the index of the item being edited and refreshes the staff grid
        /// </summary>
        /// <param name="source">source of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnEditStaffPerson(object source, DataGridCommandEventArgs e)
        {
            try
            {
                if (staffGrid.EditItemIndex > -1 || nonStudyStaffGrid.EditItemIndex > -1)
                {
                    warning.Visible = true;
                    return;
                }
                staffGrid.EditItemIndex = e.Item.ItemIndex;
                BindStaffGrid();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// The item being edited gets cast to a a StaffPerson and the editable values are set on the 
        /// StaffPerson and it is called on to save itself.  The index of the item is then reset to -1 
        /// and the staff grid is refreshed to reflect the updates
        /// </summary>
        /// <param name="source">source of the event</param>
        /// <param name="e">arguments of the event</param>
        private void OnUpdateStaffPerson(object source, DataGridCommandEventArgs e)
        {
            try
            {
                if (((CheckBox) e.Item.Cells[(int) StaffColumnIndex.Remove].Controls[1]).Checked)
                {
                    RemoveStaffPerson(e.Item);
                }
                else
                {
                    StaffPerson person = (protocolProcessId > 0) ?
                                                                     (StaffPerson) ProtocolProcess.StudyStaff[e.Item.ItemIndex] :
                                                                                                                                    (StaffPerson) Protocol.StudyStaffList[e.Item.ItemIndex];

                    if (!PermitStaffingUpdate(person, e.Item))
                    {
                        return;
                    }

                    UpdateStaffPersonObject(person, e.Item);

                    SqlConnection conn = new SqlConnection(DataAccess.GetConnectionString());
                    SqlTransaction trans = null;

                    try
                    {
                        conn.Open();
                        trans = conn.BeginTransaction();
                        person.Save(trans);
                        UpdateAMEForm(person, true);
                        UpdateProtocol(person, trans);
                        trans.Commit();
                        warning.Visible = false;
                    }
                    catch (Exception ex)
                    {
                        trans.Rollback();
                        DisplayExceptionReport(ex);
                    }
                    finally
                    {
                        if (conn.State != ConnectionState.Closed)
                        {
                            conn.Close();
                        }
                    }
                }
                /* Setting the studyStaff to null will force a refresh when the grid is loading */
                if (protocolProcessId > 0)
                {
                    ProtocolProcess.Validated = false;
                    ProtocolProcess.StudyStaff = null;
                }
                else
                {
                    Protocol.StudyStaffList = null;
                }
                staffGrid.EditItemIndex = -1;
                BindStaffGrid();
                ToggleCertificationFormUploadSectionVisibility();
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Disables editing of staffing grid if the user doesn't have manage access to the protocol
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        protected void OnStaffDataBound(object sender, EventArgs e)
        {
            try
            {
                /* Turn off edit column if user doesn't have manage or edit access to this protocol
				 * (only show for edit access if the protocol is all editable since locked protocols
				 * only have editable permissions and users with edit access can't modify these */
                staffGrid.Columns[(int) StaffColumnIndex.Edit].Visible =
                    (IsAllEditable && ((userAccessLevel & Protocol.EditPermission) > 0))
                        || ((userAccessLevel & Protocol.ManagePermission) > 0);

                staffGrid.Columns[(int) StaffColumnIndex.Remove].Visible = IsAllEditable &&
                    ((userAccessLevel & (Protocol.ManagePermission |
                        Protocol.EditPermission)) > 0);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Disables editing of nonstaffing grid if the user doesn't have manage or edit access to the protocol
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        protected void OnNonStaffDataBound(object sender, EventArgs e)
        {
            try
            {
                /* Turn off edit and remove column if user doesn't have manage or edit access to this protocol */
                nonStudyStaffGrid.Columns[(int) NonStaffColumnIndex.Edit].Visible =
                    nonStudyStaffGrid.Columns[(int) NonStaffColumnIndex.Remove].Visible = ((userAccessLevel &
                        (Protocol.ManagePermission |
                            Protocol.EditPermission)) > 0);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Handles the changing of a role in the dropdownlist to update the permissions accordingly.  If
        /// the person is staffed as the PI or the Co-PI, the permissions are set to "Manage" in the 
        /// dropdownlist.  If some other role is selected (as long as the person is not a contact person), 
        /// the permissions are changed to "Edit".
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        protected void OnRoleChange(object sender, EventArgs e)
        {
            try
            {
                /* Dropdownlist's immediate parent is the tableCell, whose parent is the DataGridItem */
                DropDownList roles = (DropDownList) sender;
                DataGridItem item = roles.Parent.Parent as DataGridItem;
                DropDownList permission =
                    (DropDownList) item.Cells[(int) StaffColumnIndex.Permission].FindControl("permissionsList");
                CheckBox contact =
                    (CheckBox) item.Cells[(int) StaffColumnIndex.ContactPerson].FindControl("contact");

                /* If permission = string.Empty, this person cannot be assigned access (no logon) */
                if (permission.SelectedValue != string.Empty)
                {
                    if ((roles.SelectedValue == SitePIIRoleTyped) || (roles.SelectedValue == PIIRoleTyped))
                    {
                        permission.SelectedValue =
                            Permissions.Select(string.Format("{0} = 'Manage'", PermissionsNameColumn))[0]
                                [PermissionsBitValueColumn].ToString();

                        permission.Enabled = false;
                        contact.Enabled = false;
                        contact.Checked = true;
                    }
                    else
                    {
                        if (!contact.Checked)
                        {
                            permission.SelectedValue =
                                Permissions.Select(string.Format("{0} = 'Edit'", PermissionsNameColumn))[0]
                                    [PermissionsBitValueColumn].ToString();
                        }

                        permission.Enabled =
                            ((userAccessLevel & Protocol.ManagePermission) > 0);
                        contact.Enabled = true;
                    }
                }
                else
                {
                    item.Cells[(int) StaffColumnIndex.Permission].Controls.Remove(permission);
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Handles the unchecking and checking of the Contact checkbox by updating permissions accordingly.
        /// If the person is a contact person, permissions are updated to "Manage".  Otherwise, they are set
        /// to "Edit" unless the person is staffed as the PI or Co-PI
        /// 
        /// Also: Sets the flag to updateRex to true (as long as this isn't a Work in progress since then it
        /// wouldn't exist in REX yet) since we always need to push over contact designation changes
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments of the event</param>
        protected void OnContactChange(object sender, EventArgs e)
        {
            try
            {
                CheckBox contact = (CheckBox) sender;
                DataGridItem item = (DataGridItem) contact.Parent.Parent;
                DropDownList permission =
                    (DropDownList) item.Cells[(int) StaffColumnIndex.Permission].FindControl("permissionsList");

                /* If permission = string.Empty, this person cannot be assigned access (no logon) */
                if (permission.SelectedValue != string.Empty)
                {
                    if (contact.Checked)
                    {
                        permission.SelectedValue =
                            Permissions.Select(string.Format("{0} = 'Manage'", PermissionsNameColumn))[0]
                                [PermissionsBitValueColumn].ToString();
                    }
                    else
                    {
                        string role = string.Empty;
                        TableCell roleCell = item.Cells[(int) StaffColumnIndex.Role];

                        string addedProcessId = ((TextBox)
                            item.Cells[(int) StaffColumnIndex.AddedProtocolProcessId].Controls[0]).Text;

                        if (CheckRoleMaintainability(
                            (addedProcessId == string.Empty) ? 0 : Convert.ToInt32(addedProcessId)))
                        {
                            DropDownList roles = roleCell.FindControl(roleDropDownListId) as DropDownList;
                            if (roles != null)
                            {
                                role = roles.SelectedValue;
                            }
                        }
                        else
                        {
                            Label roleLabel = roleCell.FindControl(roleLabelId) as Label;
                            if (roleLabel != null)
                            {
                                role = roleLabel.Text;
                            }
                        }

                        if ((role != SitePIIRoleTyped) && (role != PIIRoleTyped))
                        {
                            permission.SelectedValue =
                                Permissions.Select(string.Format("{0} = 'Edit'", PermissionsNameColumn))[0]
                                    [PermissionsBitValueColumn].ToString();
                        }
                    }
                }
                else
                {
                    // No permissions to modify; remove the dropdownlist that just got re-created
                    item.Cells[(int) StaffColumnIndex.Permission].Controls.Remove(permission);
                }
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// Handles the "Add Staff" or "Begin Staffing" button click event by launching the staffing wizard
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments to the event</param>
        private void OnAddStaff(object sender, ImageClickEventArgs e)
        {
            try
            {
                if (staffGrid.EditItemIndex > -1 || nonStudyStaffGrid.EditItemIndex > -1)
                {
                    warning.Visible = true;
                    return;
                }
                CacheOutgoingData(showAsPopUp);
                Response.Redirect(Settings.GetKeyValue("SubModuleNavigation.Humans.AddStaffURL",
                    "AddStaff.aspx"), false);
            }
            catch (Exception ex)
            {
                DisplayExceptionReport(ex);
            }
        }

        /// <summary>
        /// This event will add the person selected in the Submitter
        /// drop down box to the Study Staff from the Non Study Staff.
        /// If the person is already part of the Study Staff, no
        /// change will take affect.
        /// </summary>
        /// <param name="sender">sender of the event</param>
        /// <param name="e">arguments to the event</param>
        private void OnAddSubmitterToStaff(object sender, ImageClickEventArgs e)
        {
            if (staffGrid.EditItemIndex > -1 || nonStudyStaffGrid.EditItemIndex > -1)
            {
                warning.Visible = true;
                return;
            }
            // we don't need to check if we're in the context of a process or a protocol
            // since we only show the button during a process that is a work in process
            ArrayList staff = ProtocolProcess.StudyStaff;
            StaffPerson person;
            for (int i = 0, count = staff.Count; i < count; ++i)
            {
                person = (StaffPerson) staff[i];
                if (person.Person.UserId == ProtocolProcess.SubmitterId)
                {
                    return;
                }
            }

            // if we reach this code, the person has not already been staffed
            ArrayList nonStaff = ProtocolProcess.NonStudyStaff;
            for (int i = 0, count = nonStaff.Count; i < count; ++i)
            {
                NonStaffPerson nonStaffPerson = (NonStaffPerson) nonStaff[i];
                if (nonStaffPerson.Person.UserId == ProtocolProcess.SubmitterId)
                {
                    int permissionLevel = Protocol.ManagePermission;
                    person = new StaffPerson(cachePolicy, permissionLevel);
                    person.ModuleType = Protocol.ModuleType;

                    person.Person.Load(DataAccess.ConnectionString, nonStaffPerson.AdmPersonId);
                    person.OrganizationId = person.Person.OrganizationId;
                    person.OrganizationName = person.Person.OrganizationName;
                    person.RoleId = 0;
                    person.IsContactPerson = true;

                    ProtocolProcess.AddStudyStaff(person);
                    ProtocolProcess.Save(DataAccess.ConnectionString);
                    ProtocolProcess.NonStudyStaff = null;
                    BindStaffGrid();
                    BindNonStaffGrid();
                    ToggleCertificationFormUploadSectionVisibility();
                    return;
                }
            }
        }

        /// <summary>
        /// Ties the certification form selected by the user to the selected external staff
        /// </summary>
        /// <param name="sender">Object that raised the event</param>
        /// <param name="e">Arguments associated with the event</param>
        protected void OnImgBtnUploadCertificationFormClick(object sender, EventArgs e)
        {
            HttpPostedFile postedFile = fuCertificationForm.PostedFile;
            if (postedFile != null)
            {
                try
                {
                    string fileName = Path.GetFileName(postedFile.FileName);
                    if (postedFile.ContentLength > 0)
                    {
                        //store uploaded files in a temporary location, virus scan & upload it to database & set the documentId column of the datatable
                        string filePath = Path.Combine(Path.GetTempPath(), Path.GetTempFileName());

                        postedFile.SaveAs(filePath);

                        if (bool.Parse(Settings.GetKeyValue("VirusScanner.Enable", "false")))
                        {
                            try
                            {
                                Document.ScanFileForVirus(filePath);
                            }
                            catch (Exception ex)
                            {
                                throw new Exception(string.Format("Virus scan on {0} failed.\r\nFailure Details: {1}", fileName, ex.Message));
                            }
                        }

                        FileStream fs = new FileStream(filePath, FileMode.OpenOrCreate, FileAccess.Read);
                        byte[] data = new byte[fs.Length];
                        fs.Read(data, 0, Convert.ToInt32(fs.Length));
                        fs.Close();
                        Document consentForm = new Document(new NullCachePolicy());
                        consentForm.Blob = data;
                        consentForm.Name = "ConsentForm.pdf";
                        consentForm.Save(DataAccess.ConnectionString);

                        ArrayList staff = (protocolProcessId == 0) ? Protocol.StudyStaffList : ProtocolProcess.StudyStaff;
                        foreach (StaffPerson sp in staff)
                        {
                            if (sp.Id.ToString() == ddlSelectedExternalPeople.SelectedValue)
                            {
                                sp.UpdateCertificationId(consentForm.Id);
                                if (protocolProcessId == 0)
                                {
                                    Protocol.StudyStaffList = null;
                                }
                                else
                                {
                                    ProtocolProcess.StudyStaff = null;
                                }
                                BindStaffGrid();
                                LoadStaffWithoutCertification();
                                break;
                            }
                        }

                        File.Delete(filePath);
                    }
                    else
                    {
                        throw new Exception(fileName + " is empty or invalid;" + "\r\n");
                    }
                }
                catch (Exception ex)
                {
                    annunciator.Message = ex.Message;
                    ExceptionReport.WriteToEventLog("StaffAndAccess.OnBtnUploadCertificationFormClick(): Failed to process the uploaded file", ex, true, ExceptionReport.ReportType.Error);
                }
            }
        }

        #endregion

        #region Enumerations

        #region Nested type: NonStaffColumnIndex

        /// <summary>
        /// Columns in the nonstaffing grid in the order they appear
        /// </summary>
        private enum NonStaffColumnIndex
        {
            Id,
            LastName,
            FirstName,
            UserName,
            Organization,
            Comments,
            ContactPerson,
            Permission,
            Remove,
            Edit
        }

        #endregion

        #region Nested type: StaffColumnIndex

        /// <summary>
        /// Columns in the staffing grid in the order they appear
        /// </summary>
        private enum StaffColumnIndex
        {
            LastName,
            FirstName,
            UserName,
            Role,
            Organization,
            ContactPerson,
            Permission,
            CitiCertified,
            CertificationDate,
            AmeNumber,
            Status,
            ViewConsent,
            Remove,
            AddedProtocolProcessId,
            Edit
        }

        #endregion

        #endregion
    }
}